Вывод Меток на Яндекс Картах по адресу

Автоматическое добавление на карту любых точек по адресу (Филиалы, дилеры, офисы по стране).

Для одного из проектов понадобилось удобно разместить на Яндекс-карте офисы всех дилеров компании по стране. Желательно конечно автоматизировать процесс, чтобы все далее добавленные офисы автоматически добавлялись на карту, без копания в коде и прописывания координат каждой новой точки.

Удалось набросать отличное, полностью автоматизированное решение, которое добавляет офис на карту, оперируя лишь адресом офиса.

Ситуация довольно распространенная, потому думаю будет не лишним поделиться опытом.


Дано:
Каталог Дилеры в дереве ресурсов, внутри страницы-ресурсы. Каждая страница — это отдельный офис.
Заполняем адреса офисов в отведенном для этого поле. Я возьму для этого description, но без проблем можно взять и TV.

Адрес может быть написан в любом формате, чем подробнее, тем лучше. Например г. Москва, ул. Ак. Королева 12.

Как разместить стандартную Яндекс карту на сайте, думаю все знают.

  1. Убедимся, что подключен Jquery — актуальной версии
  2. Подключаем скрипт карты
    <script src="https://api-maps.yandex.ru/2.1/?lang=ru-RU" type="text/javascript"></script>
  3. Размещаем контейнер карты
    <div id="map" style=" height: 400px"></div>
Следующий этап — настроем получение координат по адресу. В этом нам поможет сервис геокодирования Яндекс карт. Мы делаем HTTP запрос сервису, передавая ему произвольную строку с адресом — он возвращает массив данных, среди которых в том числе есть и координаты для карты.

Хотите посмотреть как он работает? Нет ничего проще.
Перейдите по ссылке
https://geocode-maps.yandex.ru/1.x/?geocode=Ваш_адрес
Пример ссылки

По умолчанию данные возвращаются в XML формате.
Мне привычнее работать с JSON, поэтому я прошу сервис отдать мне JSON массив.
https://geocode-maps.yandex.ru/1.x/?format=json&geocode=Ваш_адрес
Следующий вопрос — каким образом провести HTTP запрос к сервису?
Опытные разработчики на этом месте улыбнутся, но не для всех это очевидно.
Для HTTP запросов используем программу cURL, которая позволяет обращаться к любому серверу и забирать данные.

Выглядит это так.

//Функция может быть в любом месте кода
function curl_get_contents($url){
	$curl = curl_init($url);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
	$data = curl_exec($curl);
	curl_close($curl);
	return $data;
}
// Пишем адрес, к которому обращаемся
$url = 'https://geocode-maps.yandex.ru/1.x/?format=json&geocode=Ваш_адрес';
// Получаем ответ от сервера
$response = curl_get_contents($url);
// $response - это готовый json массив с данными. 
// Преобразуем json в обычный массив
$response = json_decode($response, true);
// Получаем из массива координаты для карты.
$point = $response['response']['GeoObjectCollection']['featureMember'][0]['GeoObject']['Point']['pos'];
// Почему то координаты отдаются не в том порядке. Для карты нужно поменять местами широту и долготу плюс меняем пробел на запятую
$point = explode(' ', $point);
$point = implode(', ', array_reverse($point));
// На этом этапе мы уже имеем точку с координатами, которую остается отдать карте.

Автоматизируем наш пример и получаем координаты конкретных адресов, которые уже есть у нас в админке

function curl_get_contents($url){
	$curl = curl_init($url);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
	$data = curl_exec($curl);
	curl_close($curl);
	return $data;
}
// Указываем id каталога с дилерами
$dillers = 90;
// Запросы к базе делаем через класс PDOTools. Это быстрее
$pdo = $modx->getService('pdoFetch');
// Получаем всех дилеров
$offices = $pdo->getcollection('modResource', array('parent' => $dillers));
// Указываем в каком поле у нас лежит адрес 
$field = 'description';
//В цикле получаем координаты каждого офиса.
$i = 0;
$features = '';
foreach($offices as $office){
	 if(!empty($office[$field])){
		$url = 'https://geocode-maps.yandex.ru/1.x/?format=json&geocode='.$office[$field];
		$response = json_decode(curl_get_contents($url), true);
     		$point = $response['response']['GeoObjectCollection']['featureMember'][0]['GeoObject']['Point']['pos'];
     		$point = explode(' ', $point);
     		$point = implode(', ', array_reverse($point));
		$features .= '
     		{
        		"type": "Feature", 
        		"id": '.$i.', 
        		"geometry": {"type": "Point", "coordinates": ['.$point.']}, 
        		"properties": {"balloonContent": "<h3>'.$office['pagetitle'].'</h3>", "clusterCaption": "", "hintContent": ""}			
     		 },
    		 ';
//В поле balloonContent Вы можете вставить любой текст, он появится при клике на метку. Например номер телефона. Можно HTML. Не забывайте экранировать кавычки в html.
     		$i ++;
	}
return '{
      "type": "FeatureCollection",
      "features": ['.$features.']
  }';  
}

Сохраняем сниппет getDillesCoords, который должен вернуть нам примерно следующий JSON массив.

{
    "type": "FeatureCollection",
    "features": [
        {"type": "Feature", "id": 0, "geometry": {"type": "Point", "coordinates": [55.831903, 37.411961]}, "properties": {"balloonContent": "Содержимое балуна", "clusterCaption": "Еще одна метка", "hintContent": "Текст подсказки"}},
        {"type": "Feature", "id": 1, "geometry": {"type": "Point", "coordinates": [55.763338, 37.565466]}, "properties": {"balloonContent": "Содержимое балуна", "clusterCaption": "Еще одна метка", "hintContent": "Текст подсказки"}},
        {"type": "Feature", "id": 2, "geometry": {"type": "Point", "coordinates": [55.763338, 37.565466]}, "properties": {"balloonContent": "Содержимое балуна", "clusterCaption": "Еще одна метка", "hintContent": "Текст подсказки"}},
        {"type": "Feature", "id": 3, "geometry": {"type": "Point", "coordinates": [55.744522, 37.616378]}, "properties": {"balloonContent": "Содержимое балуна", "clusterCaption": "Еще одна метка", "hintContent": "Текст подсказки"}},
        {"type": "Feature", "id": 4, "geometry": {"type": "Point", "coordinates": [55.780898, 37.642889]}, "properties": {"balloonContent": "Содержимое балуна", "clusterCaption": "Еще одна метка", "hintContent": "Текст подсказки"}},
        {"type": "Feature", "id": 5, "geometry": {"type": "Point", "coordinates": [55.793559, 37.435983]}, "properties": {"balloonContent": "Содержимое балуна", "clusterCaption": "Еще одна метка", "hintContent": "Текст подсказки"}},
    ]
}

Остается вызвать карту и передать в нее содержимое сниппета.
Пишем JS скрипт рядом с нашим контейнером #map

<script src="https://api-maps.yandex.ru/2.1/?lang=ru-RU" type="text/javascript"></script>
<div id="map" style=" height: 400px"></div>
<script>

ymaps.ready(init);

function init () {
    var myMap = new ymaps.Map('map', {
            //Укажите центр карты и масштаб, чтобы было видно все точки
	    center: [55.76, 37.64],
            zoom: 4
        }, {
            searchControlProvider: 'yandex#search'
        }),
//Различные технические настройки
        objectManager = new ymaps.ObjectManager({
            clusterize: true,
            gridSize: 32
        });
    objectManager.objects.options.set('preset', 'islands#greenDotIcon');
    objectManager.clusters.options.set('preset', 'islands#greenClusterIcons');
    myMap.geoObjects.add(objectManager);
   
    //Вызываем сниппет, получаем JSON массив с координатами офисов и добавляем их на карту
    objectManager.add([[!getDillesCoords]]);

}
</script>
Николай Савин
22 апреля 2017, 13:39
modx.pro
16
7 892
+7
Поблагодарить автора Отправить деньги

Комментарии: 7

UDAV
22 апреля 2017, 18:16
+3
Это разве не то? modstore.pro/packages/other/yandexmaps
    Николай Савин
    22 апреля 2017, 18:19
    -3
    Нет.
    1. Там старая версия Api
    2. Там все равно нужно координаты указывать в TV
      UDAV
      22 апреля 2017, 18:30
      +1
      2.1 это разве старая? у тебя такая же используется -)… да и вообще это последняя версия и она уже давно не меняется.
      там можно адрес указать, причем с поиском… а координаты подставляются сами.
        Николай Савин
        22 апреля 2017, 18:32
        +1
        Ну может. Я не вникал и аналогов не искал.
        Появилась задача — сделал — рассказал как.
        Спасибо за наводку.
    but1head
    23 апреля 2017, 11:08
    +2
    Тоесть при каждой загрузке страницы идет 6 запросов на геокодинг? Это не серьезно, про лимиты запросов 10.000 / день (вроде) я вообще молчу. Если так не нравятся tv — сохраняй в properties страницы, там как раз json.
      Кирилл
      24 апреля 2017, 06:06
      0
      Тоже первым делом обратил на это внимание. Я бы на сохранение ресурса повесил плагин. Можно еще записать старый адрес и в момент сохранения проверять, изменился он или нет, это избавит еще от лишних запросов.
      yani
      04 мая 2017, 15:31
      0
      Интересное решение, я использую ТВ параметр яндекс карта. где маркером выставляется нужная координата.
      Потому что очень часто сталкивалась с тем, что неточно геокодируется адрес
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        7