Пожалуй, воды хватит. Задача обрисована, как выглядит решение: это симбиоз компонентов Битрикса и API-яндекс.карт. Для фильтрации использовался «умный фильтр» битрикса, массив arrFilter передается json-ом в ajax файлик, где происходит выборка элементов инфоблока и обратно возвращаем json, понятный API-яндекс.карт. Пользователь видит коллекцию объектов. Прокладка маршрута осуществляется с помощью API-яндекс.карт, а вот фильтрация объектов вдоль пути задача не тривиальная. Именно здесь пришлось прибегнуть к помощи ТП яндекса. Маршрут представляет из себя массив GPS координат и прямо скажем этот массив совсем не маленький. Простая логика подсказывает, что нужно взять каждую точку маршрута и сравнить с ней на удаленность все остальные точки. Предположим мы имеем 5000 объектов на карте и 2000 точек на пути, если не приводить цифры, то ожидание браузера для такого расчета составляет около 2-х минут, он даже успевает поинтересоваться нужно ли ждать отклик страницы. В общем от оптимизации не уйти. Перебор решается с помощью стрелочных функций JS, что лично для меня было новостью, но в конечном итоге решение изящное. Дописываю позже: стрелочные функции не работают в IE и Edge (пришлось переписать на анонимные функции, надеюсь эти браузеры умрут совсем). Количество точек на пути оптимизируется с помощью сторонних скриптов предложенных яндексом, оптимизация гибкая и настраиваемая в зависимости от потребностей в точности и желании получить быстрый результат. Измерение расстояния между точками пути и объектами карты не получилось осуществить с помощью метода getClosest, судя по всему этот метод работает с объектом включающем в себя точки, если точки между собой ни чем не связаны, нужно либо создать объект включающий точки в себя, либо воспользоваться функцией getDistance. Конечный итог красивенькая карта с разноцветными маркерами точек, плюс кластера отображающие процентное соотношение тех или иных цветов. В общем игрушка для заказчика, вопрос - нужно ли это пользователю, для меня остается открытым.
Реализация здесь:
Код для яндекс.карт:
ymaps.ready(init); var myMap, arrId=[], wayCreated, objectManager, myPlacemark; function init(){ suggestViewStart = new ymaps.SuggestView('suggeststart'); suggestViewEnd = new ymaps.SuggestView('suggestend'); new ymaps.SuggestView('fsuggeststart'); new ymaps.SuggestView('fsuggestend'); myMap = new ymaps.Map("map", { center: [56.726032, 65.968531], zoom: 4, } ); objectManager = new ymaps.ObjectManager({ // Чтобы метки начали кластеризоваться, выставляем опцию. clusterize: true, // ObjectManager принимает те же опции, что и кластеризатор. gridSize: 48, // Макет метки кластера pieChart. clusterIconLayout: 'default#pieChart', // Радиус диаграммы в пикселях. clusterIconPieChartRadius: 25, // Радиус центральной части макета. clusterIconPieChartCoreRadius: 15, // Ширина линий-разделителей секторов и внешней обводки диаграммы. clusterIconPieChartStrokeWidth: 3, }); myMap.geoObjects.add(objectManager); $.ajax({ url: "map.php", data: {filter: <?echo json_encode($arrFilter)?>}, }).done(function(data) { objectManager.add(data); var arAdres=[], countPoint=0, arPoints; arPoints=$('#fpointVia').find('input'); if ($('#fsuggeststart').val()!=''&&$('#fsuggestend').val()!=''){ arAdres[countPoint]=$('#fsuggeststart').val(); countPoint++; for (i=0; i<arPoints.length; i++) {arAdres[countPoint]=arPoints[i].value; countPoint++;} arAdres[countPoint]=$('#fsuggestend').val(); } else return false; ymaps.route(arAdres).then(function (route) { myMap.geoObjects.removeAll(); myMap.geoObjects.add(route); $('#flengthpath').html((route.getLength()/1000).toFixed(2)); $('#fconsumption').html((((route.getLength()/1000)*$('#fconsump100').val())/100).toFixed(2)); var points=route.getWayPoints(); var routeLines=[]; for (i=0; i<countPoint; i++) routeLines = routeLines.concat(route.getPaths().get(i).geometry); var routePoints = routeLines.map(x => x.getCoordinates()).reduce((s, x) => s.concat(x)); var newArr=[]; for (i=0; i<routePoints.length; i++) newArr[i]={x: routePoints[i][0],y: routePoints[i][1]}; var simpArr = simplify(newArr,0.005,true); var simpRoutePoints=[]; for (i=0; i<simpArr.length; i++) simpRoutePoints[i]=[simpArr[i]['x'],simpArr[i]['y']]; var arId=[]; var counter=0; arrId=[]; objectManager.setFilter(function (object) { if (simpRoutePoints.some(line => ymaps.coordSystem.geo.getDistance(line , object.geometry.coordinates) < 5000)){ arId[counter]=object; arrId[counter]=object.id; counter++; return true; } else return false; }); myMap.geoObjects.add(objectManager); myMap.setBounds([points.get(0).geometry.getCoordinates(),points.get(points.getLength()-1).geometry.getCoordinates()],{checkZoomRange: true}); $('#flistFuelSt').html(''); for (i=0; i<arId.length; i++) $('#flistFuelSt').append('<div class="adr-div"><img src="<?=SITE_TEMPLATE_PATH?>/images/oil_station.svg" class="adr-icn"><div>'+arId[i].properties.balloonContent+'</div></div>'); var moveList = 'Трогаемся,</br>', way, segments; // Получаем массив путей. for (var i = 0; i < route.getPaths().getLength(); i++) { way = route.getPaths().get(i); segments = way.getSegments(); for (var j = 0; j < segments.length; j++) { var street = segments[j].getStreet(); moveList += ('Едем ' + segments[j].getHumanAction() + (street ? ' на ' + street : '') + ', проезжаем ' + segments[j].getLength() + ' м.,'); moveList += '</br>' } } moveList += 'Останавливаемся.'; $('#flist').html(''); // Выводим маршрутный лист. $('#flist').append(moveList); }); }); } |
<?php require_once($_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/prolog_before.php'); CModule::IncludeModule("iblock"); $arItems=array(); $arSelect = Array("ID", "IBLOCK_ID", "NAME", "PROPERTY_*");//IBLOCK_ID и ID обязательно должны быть указаны, см. описание arSelectFields выше $arFilter = Array("IBLOCK_ID"=>11, "ACTIVE"=>"Y"); if (isset($_REQUEST[filter])) $arFilter=array_merge($arFilter,$_REQUEST[filter]); $res = CIBlockElement::GetList(Array(), $arFilter, false, false, $arSelect); while($ob = $res->GetNextElement()){ $arFields = $ob->GetFields(); $arProps = $ob->GetProperties(); $arrCoor=explode(',',$arProps[GPS][VALUE]); $optionsPreset = ''; if (empty($arProps[NET_TRANSOIL][VALUE])) $optionsPreset="islands#yellowFuelStationIcon"; elseif (in_array(1,$arProps[NET_TRANSOIL][VALUE])) $optionsPreset="islands#greenFuelStationIcon"; elseif (in_array(2,$arProps[NET_TRANSOIL][VALUE])) $optionsPreset="islands#blueFuelStationIcon"; elseif (in_array(3,$arProps[NET_TRANSOIL][VALUE])) $optionsPreset="islands#redFuelStationIcon"; elseif (in_array(4,$arProps[NET_TRANSOIL][VALUE])) $optionsPreset="islands#orangeFuelStationIcon"; else $optionsPreset="islands#yellowFuelStationIcon"; $arItems[]=array("type"=> "Feature", "id"=>$arFields[ID], "geometry"=> array( "type"=> "Point", "coordinates"=> [floatval($arrCoor[0]),floatval($arrCoor[1])], ), "properties"=> array( "balloonContent"=> $arFields[NAME], "clusterCaption"=> $arProps[OWNER][VALUE], "hintContent"=> $arProps[BRAND][VALUE], ), "options"=>["preset"=> $optionsPreset] ); } $arResult=array("type"=> "FeatureCollection","id"=> 0, "features"=> $arItems ); echo json_encode($arResult); ?> |