import React from 'react'; import { MapContainer, TileLayer, Marker, Popup, Polygon } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; import L from 'leaflet'; // Fix default marker icon issue with webpack delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png', iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png', shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png', }); const SearchMap = ({ tnpLat, tnpLon, maxDistance, zones }) => { const tnpPosition = [tnpLat || 53.9, tnpLon || 27.56]; const distance = maxDistance || 5.0; // Функция для создания точек сектора const createSectorPoints = (centerLat, centerLon, radiusKm, startAngle, endAngle, points = 20) => { const coords = [[centerLat, centerLon]]; // Начинаем с центра // Конвертируем км в градусы (приблизительно) const latPerKm = 1 / 111.0; const lonPerKm = 1 / (111.0 * Math.cos(centerLat * Math.PI / 180)); // Создаем точки дуги for (let i = 0; i <= points; i++) { const angle = startAngle + (endAngle - startAngle) * (i / points); const angleRad = angle * Math.PI / 180; const lat = centerLat + radiusKm * latPerKm * Math.cos(angleRad); const lon = centerLon + radiusKm * lonPerKm * Math.sin(angleRad); coords.push([lat, lon]); } coords.push([centerLat, centerLon]); // Замыкаем в центре return coords; }; // Направления и их углы const directionAngles = { 'N': 0, 'NE': 45, 'E': 90, 'SE': 135, 'S': 180, 'SW': 225, 'W': 270, 'NW': 315 }; // Создаем секторы на основе зон const sectors = zones && zones.length > 0 ? zones.slice(0, 8).map((zone, idx) => { const angle = directionAngles[zone.direction] || 0; const startAngle = angle - 22.5; // ±22.5° = 45° сектор const endAngle = angle + 22.5; // Определяем радиус на основе score let radius = distance; if (zone.score >= 90) radius = distance * 1.0; else if (zone.score >= 70) radius = distance * 0.8; else if (zone.score >= 50) radius = distance * 0.6; else radius = distance * 0.4; // Цвет на основе приоритета let color, fillOpacity; if (idx === 0) { color = '#ff4d00'; fillOpacity = 0.35; } else if (idx === 1) { color = '#ff9f1a'; fillOpacity = 0.25; } else if (idx === 2) { color = '#ffd166'; fillOpacity = 0.2; } else { color = '#8b949e'; fillOpacity = 0.1; } return { points: createSectorPoints(tnpPosition[0], tnpPosition[1], radius, startAngle, endAngle), color, fillOpacity, zone }; }) : []; // Если зон нет, создаем базовые концентрические круги const createCirclePoints = (centerLat, centerLon, radiusKm, points = 40) => { const coords = []; const latPerKm = 1 / 111.0; const lonPerKm = 1 / (111.0 * Math.cos(centerLat * Math.PI / 180)); for (let i = 0; i <= points; i++) { const angle = (i / points) * 2 * Math.PI; const lat = centerLat + radiusKm * latPerKm * Math.cos(angle); const lon = centerLon + radiusKm * lonPerKm * Math.sin(angle); coords.push([lat, lon]); } return coords; }; const defaultZones = [ { points: createCirclePoints(tnpPosition[0], tnpPosition[1], distance), color: '#ffd166', fillOpacity: 0.15, label: `Зона 3 (${distance.toFixed(1)} км)`, probability: 10 }, { points: createCirclePoints(tnpPosition[0], tnpPosition[1], distance * 0.75), color: '#ff9f1a', fillOpacity: 0.2, label: `Зона 2 (${(distance * 0.75).toFixed(1)} км)`, probability: 20 }, { points: createCirclePoints(tnpPosition[0], tnpPosition[1], distance * 0.5), color: '#ff4d00', fillOpacity: 0.3, label: `Зона 1 (${(distance * 0.5).toFixed(1)} км)`, probability: 70 } ]; return ( {/* Рисуем секторы или круги */} {sectors.length > 0 ? ( sectors.map((sector, idx) => ( #{idx + 1} {sector.zone.name}
Направление: {sector.zone.direction}
Приоритет: {sector.zone.score}%
{sector.zone.reasoning}
)) ) : ( defaultZones.map((zone, idx) => ( {zone.label}
Вероятность: {zone.probability}%
)) )} {/* ТНП - красный маркер */} ТНП - Точка начала поиска
Координаты: {tnpLat?.toFixed(6)}, {tnpLon?.toFixed(6)}
Максимальная дистанция: {distance.toFixed(1)} км
); }; export default SearchMap;