Пожалуй, воды хватит. Задача обрисована, как выглядит решение: это симбиоз компонентов Битрикса и 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);
?>
|