let crimeaDatabase = []; let currentFilterTab = 'all'; let userCoords = null; // Старт работы приложения async function startCyberEngine() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( (position) => { userCoords = { lat: position.coords.latitude, lon: position.coords.longitude }; console.log("GPS координаты получены:", userCoords); loadFuelDatabase(); }, (error) => { console.warn("GPS отклонен:", error.message); loadFuelDatabase(); }, { enableHighAccuracy: true, timeout: 5000 } ); } else { loadFuelDatabase(); } } // Загрузка данных из базы JSON async function loadFuelDatabase() { const grid = document.getElementById('cyberCardsGrid'); if (!grid) return; grid.innerHTML = '
СИНХРОНИЗАЦИЯ ИИ-МАТРИЦЫ ТОПЛИВА...
'; try { const res = await fetch('data.json?v=' + Date.now()); const rawData = await res.json(); crimeaDatabase = rawData.map(st => { const probability = calculateProbability(st.fuels, st.source, st.terms); const coords = st.lat && st.lon ? { lat: st.lat, lon: st.lon } : fallbackCoordinates(st.city); let distance = null; if (userCoords) { distance = calculateHaversineDistance(userCoords.lat, userCoords.lon, coords.lat, coords.lon); } return { ...st, probability, lat: coords.lat, lon: coords.lon, distance }; }); // Сортировка по удаленности АЗС от водителя if (userCoords) { crimeaDatabase.sort((a, b) => { if (a.fuels.length === 0) return 1; if (b.fuels.length === 0) return -1; return a.distance - b.distance; }); } else { crimeaDatabase.sort((a, b) => b.probability - a.probability); } renderCyberCards(crimeaDatabase); } catch (err) { console.error("Ошибка загрузки базы:", err); grid.innerHTML = 'КРИТИЧЕСКАЯ ОШИБКА ОБНОВЛЕНИЯ БАЗЫ.
'; } } function calculateHaversineDistance(lat1, lon1, lat2, lon2) { const R = 6371; const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return parseFloat((R * c).toFixed(1)); } function calculateProbability(fuels, source, terms) { if (!fuels || fuels.length === 0) return 0; let score = 50; const text = terms.toLowerCase(); const src = source.toLowerCase(); if (src.includes('минтопэнерго') || src.includes('официальный')) score += 20; if (src.includes('мониторинг сайта')) score += 15; if (src.includes('чат') || src.includes('народный')) score += 5; if (text.includes('свободный') || text.includes('ограничений нет')) score += 20; if (text.includes('очередь отсутствует') || text.includes('без очередей')) score += 10; if (text.includes('бензовоз был') || text.includes('завезли')) score += 15; if (text.includes('только по талонам') || text.includes('топливным картам')) score -= 35; if (text.includes('закончился') || text.includes('ожидают')) score -= 40; return Math.max(5, Math.min(100, score)); } function openYandexNavigator(lat, lon) { const naviUrl = `yandexnavi://build_route_on_map?lat_to=${lat}&lon_to=${lon}`; const webUrl = `https://yandex.ru{lat},${lon}&rtt=auto`; const start = Date.now(); window.location.href = naviUrl; setTimeout(() => { if (Date.now() - start < 600) window.open(webUrl, '_blank'); }, 500); } function fallbackCoordinates(city) { const points = { 'симферополь': { lat: 44.952117, lon: 34.102417 }, 'севастополь': { lat: 44.588837, lon: 33.522402 }, 'ялта': { lat: 44.498114, lon: 34.168541 }, 'керчь': { lat: 45.356219, lon: 36.467371 }, 'евпатория': { lat: 45.198144, lon: 33.364024 }, 'феодосия': { lat: 45.031737, lon: 35.382632 }, 'таврида': { lat: 45.054452, lon: 34.603351 } }; return points[city] || { lat: 44.952117, lon: 34.102417 }; } function renderCyberCards(dataset) { const grid = document.getElementById('cyberCardsGrid'); if (!grid) return; grid.innerHTML = ''; if (dataset.length === 0) { grid.innerHTML = 'ЛОКАЦИИ НЕ НАЙДЕНЫ.
'; return; } dataset.forEach(st => { const card = document.createElement('div'); card.className = 'cyber-card'; let colorClass = '#ef4444'; if (st.probability >= 40 && st.probability < 75) colorClass = '#f59e0b'; if (st.probability >= 75) colorClass = '#22c55e'; const badge95 = st.fuels.includes('АИ-95') ? 'on-95' : ''; const badge92 = st.fuels.includes('АИ-92') ? 'on-92' : ''; const badgeDt = st.fuels.includes('ДТ') ? 'on-dt' : ''; const distanceHtml = st.distance !== null ? `