Часто перед разработчиками сайта встаёт задача отразить на интерактивной карте местоположение каких-либо объектов. Например филиалов компании, магазинов, автозаправочных станций и т.д. Формировать карту в конструкторе яндекс карт каждый раз при появлении нового объекта — неудобно. Для решения этой задачи лучше воспользоваться API Яндекс карт и большими возможностями 1С Битрикс.
И так, разобьём работу на этапы:
- Установка продукта
- Подготовка инфоблока
- Подготовка компонента
- Внедрение JavaScript формирующего Яндекс карту
Установка продукта
Не стану подробно останавливаться на этом вопросе, думаю ни у кого он не вызывает трудностей. Дам лишь совет, пользоваться кодировкой UTF-8 она в любом случае выгоднее т.к. содержит больше символов нежели кирилица Windows (или windows-1251 стандартная битрикс кодировка). Кодировку можно указать во время установки продукта на 3-м шаге «Регистрация»:
Если на следующем шаге будут ошибки , обычно ругается на mbstring.func_overload и mbstring.internal_encoding в файл .htaccess в папке с устанавливаемой CMS укажите следующие директивы и продолжайте установку:
php_value mbstring.func_overload 2 php_value mbstring.internal_encoding UTF-8
На этом всё, переходим к настройке информационного блока.
Подготовка информационного блока
Давайте определимся что мы хотим получить. Допустим у нас есть несколько магазинов которые мы хотим показывать на интерактивной яндекс карте + давать пользователям какую-нибудь доп. информацию о них, например точный адрес магазина, часы работы, контактный телефон и ФИО руководителя. Т.е. по клику на точку на яндекс карте, мы увидим некий блок, так называемый балун с доп. информацией о магазине. Для формирования самой точки на карте, нам потребуется задавать её координаты, для этого в 1С Битрикс существует тип поля привязка к Яндекс карте.
Приступим! Создаём инфоблок «Магазины&qout; со следующими свойствами (Имя свойства — тип — мнемонический код):
- Адрес магазина — тип строка — ADDRESS
- Часы работы — тип строка — HOURS
- Контактный телефон — тип строка — PHONE
- ФИО руководителя — тип строка — SHOP_MANAGER
- Координаты — тип привязка к яндекс карте — YANDEX_MAP
Сохраняем инфоблок и добавляем в него несколько элементов, я добавил 3 магазина с 3-мя адресами в разных районах города Ростов-на-Дону. Важно при добавлении магазинов указать адрес на интерактивной карте Яндекс и сделать двойной щелчёк по заданной точке, чтобы заполнились поля координат точки иначе не получится построить точку на карте.
Добавив несколько элементов переходим к следующему этапу.
Подготовка компонета
Для реализации задумки я решил использовать компонент bitrix:news.list, с его помощью мы выведем на экран список магазинов, данные для формирования карты и контейнер для самой карты. Для того чтобы JavaScript смог построить интерактиыную карты, ему нужно отдать данные объектов, т.е. данные наших магазинов. Для этого есть 2 способа.
- Вывести данные оъектов в специальные атрибуты тегов, т.е. непосредственно в DOM дерево документа
- Подготовить структурированный массив в php и затем с помощью функции 1С Битрикс PhpToJSObject преобразовать массив в JavaScript объект и затем работать с этим JS обектом вытаскивая данные для формирования карты.
Лично я предпочитаю первый способ, т.к. считаю его более наглядным и понятным. И так скопируем компонент news.list в текущий шаблон сайта с помощью интерфейса «Эрмитаж» и укажем следующий код шаблона:
<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();?> <div class="shop-list"> <? $index = 1; // Порядковый номер объекта на карте foreach($arResult["ITEMS"] as $arItem) { ?> <? $this--->AddEditAction($arItem['ID'], $arItem['EDIT_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_EDIT")); $this->AddDeleteAction($arItem['ID'], $arItem['DELETE_LINK'], CIBlock::GetArrayByID($arItem["IBLOCK_ID"], "ELEMENT_DELETE"), array("CONFIRM" => GetMessage('CT_BNL_ELEMENT_DELETE_CONFIRM'))); ?> <? //Разбиваем координаты яндекс карты на X и Y координату $Yandex = explode(",", $arItem["PROPERTIES"]["YANDEX_MAP"]["VALUE"]); $Yandex_X = $Yandex[0]; $Yandex_Y = $Yandex[1]; ?> <!--Засовываем данные для формирования точки на карте в атрибуты контейнера div--> <div class="shop-data" data-index="<?=$index?>" data-name="<?=$arItem[" name"]?>" data-yandex-x="<?=$Yandex_X;?>" data-yandex-y="<?=$Yandex_Y;?>" data-address="<?=$arItem["PROPERTIES"]["ADDRESS"]["VALUE"];?>" data-hours="<?=$arItem["PROPERTIES"]["HOURS"]["VALUE"];?>" data-phone="<?=$arItem["PROPERTIES"]["PHONE"]["VALUE"];?>" data-shop-manager="<?=$arItem["PROPERTIES"]["SHOP_MANAGER"]["VALUE"];?>" > <!--Выводим информацию для пользователя--> <b><?=$arItem["NAME"]?></b> <ul> <li><b>Адрес:</b> <?=$arItem["PROPERTIES"]["ADDRESS"]["VALUE"];?></li> <li><b>Часы работы:</b> <?=$arItem["PROPERTIES"]["HOURS"]["VALUE"];?></li> <li><b>Контактный телефон:</b> <?=$arItem["PROPERTIES"]["PHONE"]["VALUE"];?></li> <li><b>ФИО руководителя:</b> <?=$arItem["PROPERTIES"]["SHOP_MANAGER"]["VALUE"];?></li> </ul> </div> <? ++$index; } unset($index); ?> <!--Контейнер в который прилетит сформированная яндекс карта--> <div id="map_container"></div> </div>
Давайте так же заранее пропишем css стили для контейнера карты, и точек (маркеров) на самой карте
#map_container { width:100%; height:600px; display:block; } .marker-circ { color: #404040; font-size: 14px; font-weight: normal; height: 80px; line-height: 56px; width: 58px; } .claster { color: #ffffff; font-size: 14px; font-weight: bold; height: 80px; line-height: 56px; width: 58px; }
Компонент готов, можно переходить к подключению JavaScript сформирующего нам яндекс карту.
Внедрение JavaScript Яндекс карты
Первым делом подключаем JQuery (в моём случае это jQuery v1.9.1) и скрипт яндекс карты, чтобы не держать лишьних скриптов на сервере можно воспользоваться удалёнными файлами.
<script src="http://yandex.st/jquery/1.9.1/jquery.min.js"></script> <script src="http://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
Затем в отдельном JavaScript файле (назовём его start.js), куда мы будем выносить все наши скрипты (чтобы не писать их прям в DOM дереве документа) пишем код:
$(document).ready(function(){ //Если на странице есть контейнер для яндекс карты с id map_container, начинаем её формировать if($("#map_container").length > 0) { //yandex map ymaps.ready(function() { var map = new ymaps.Map("map_container", { center: [47.223572, 39.725845], //Создаём карту с центром в городе "Ростов-на-Дону" zoom: 11, //Увеличение 11 }); //Кластера - группируем близко расположенные друг к другу объекты, чтобы при отдалении карты появлялась другая иконка // с количеством объектов в данной точке var ClusterContent = ymaps.templateLayoutFactory.createClass('<div class="claster">$[properties.geoObjects.length] шт.</div>'); //Параметры иконки кластера, обычно её делают отличной от точки, чтобы пользователь не путал номер объекта // и количество объектов var clusterIcons=[{ href: '/bitrix/templates/furniture_pale-blue/images/map-claster.png', size:[58, 80], offset:[-24, -80], }]; //Создание самого кластера myClusterer = new ymaps.Clusterer({ clusterIcons: clusterIcons, clusterNumbers:[1], zoomMargin: [30], clusterIconContentLayout: ClusterContent }); //HTML шаблон балуна, того самого всплывающего блока, который появляется при щелчке на карту var myBalloonLayout = ymaps.templateLayoutFactory.createClass( '<address class="address-map">'+ ' <p><strong>$[properties.name]</strong>'+ ' <br /> '+ '</p> <ul class="balloon-info">'+ ' <li><strong>Адрес: </strong>$[properties.address]</li> '+ ' <li><strong>Часы работы: </strong>$[properties.hours]</li> '+ ' <li><strong>Телефон: </strong>$[properties.phone]</li> '+ ' <li><strong>Руоководитель: </strong>$[properties.manager]</li> '+ '</ul> '+ '</address>' ); var Placemark = {}; //Пустой объекта, куда будут помещены точки на для карты //Перебираем все блоки с картой и считываем данные для формирования точки и балуна по ранее заданному шаблону $(".shop-data").each(function(){ //Координаты точки var X = $(this).attr("data-yandex-x"); var Y = $(this).attr("data-yandex-y"); Obj = $(this).attr("pointindex"); //Создаём объект с заданными координатами и доп.свойствами Placemark[Obj] = new ymaps.Placemark([X,Y], { name: $(this).attr("data-name"), //Наименование магазина address: $(this).attr("data-address"), //Адрес hours: $(this).attr("data-hours"), //Часы работы phone: $(this).attr("data-phone"), //Контактный телефон manager: $(this).attr("data-shop-manager"), //Руководитель iconContent: "<div class="marker-circ">"+$(this).attr("data-index")+"</div>", //Порядковый номер на карте },{ //Ниже некоторые параметры точки и балуна balloonContentLayout: myBalloonLayout, balloonOffset: [5,0], balloonCloseButton: true, balloonMinWidth: 450, balloonMaxWidth:450, balloonMinHeught:150, balloonMaxHeught:200, iconImageHref: '/bitrix/templates/furniture_pale-blue/images/map.png', //Путь к картинке точки iconImageSize: [58, 80], iconImageOffset: [-24, -80], iconLayout: 'default#imageWithContent', iconactive: '/bitrix/templates/furniture_pale-blue/images/map-a.png' //Путь к картинке точки при наведении курсора мыши }); //Добавляем маркер (точку) через кластер myClusterer.add(Placemark[Obj]); }); //Добавление кластеры на карту map.geoObjects.add(myClusterer); //Запрещаем изменение размеров карты по скролу мыши map.behaviors.disable("scrollZoom"); }); } });
Картинки для точек на карте я скачал с сайта www.iconfinder.com — это зарубежный поисковик по иконкам, многие из которых можно скачать абсолютно бесплатно, что я собственно и сделал. А на этом сервисе от яндекса удобно получать координаты точек и центра карты.
Если Вы всё сделали правильно у Вас должна получиться вот такая карта:
Если что-то не получилось, можете ознакомиться с исходниками. Желаю удачи!
Интересное решение — очень помогло в одном проекте. Но есть вопрос: А как реализовать 2 разных вида метки, например с мощью управления из инфоблока. Допустим отметил чекбокс в инфоблоке и данный элемент вывелся с другой картинкой меткой? Я естественно не лажу с API Яндекса и js в принципе …
Ну смотрите, данные для формирования карты у меня передаются в DOM (т.е. в атрибуты тегов). откуда я их потом считываю js скриптом и запускаю карту. В параметрах скрипта в моём примере картинка маркера (точки) определена заранее «iconImageHref: ‘/bitrix/templates/furniture_pale-blue/images/map.png’, //Путь к картинке точки» — но вы можете вместо «/bitrix/templates/furniture_pale-blue/images/map.png» подгружать свою картинку из атрибута тега. Т.е. в инфоблоке ставим радиобокс «картинка 1», «картинка 2» в зависимости от галочки в в какой-нибудь атрибут тега (например data-markerimage) выводим путь к картинке. ну а в js соответственно считываем его как в свойство «iconImageHref: $(this).attr(‘data-markerimage’)» или так «iconImageHref: $(this).data(‘markerimage’)». Вуаля =)
Очень полезная статья, огромное спасибо.
Но есть вопрос, почему задваевается сформированная карта, получается одна карта располагается как бы над другой, и все метки встают только на нижнюю карту, на верхней их не видно, только номера, хотя балуны срабатывают на обоих картах.
Я думаю у вас просто ошибка в оформлении, проверьте CSS тех блоков в которые вы размещаете яндекс карту.
Отличная статья, большое спасибо! Возможно не много не по теме кластеризации, но относящийся к картам. Подскажите пожалуйста, как можно настроить Поиск по свойствам? Например выводить форму с чекбоксами, которые в свою очередь проверяют 0 или 1, Да или Нет и т.д. и убирают\добаваляют точки на карту, без перезагрузки страницы.
Ну смотрите, делайте вначале обычную формы с перезагрузкой, если речь идёт о битриксе вот тут можно посмотреть самую простейшую реализацию фильтра (без использования компонента). Получили фильтр с перезагрузкой страницы — отлично, дальше навешиваем jquery ajax, т.е. по кнопке «фильтровать» (или при нажатии на чекбокс) отправляем данные через POST на эту же страницу (смотрите jquery change()). Результат запроса обрабатываете в jquey ajax, там (в ajax ответе, обычно это переменная $(data)) находите контейнер с картой, функцией jquery html() получаете его содержимое и заменяете им содержимое текущего контейнера и перезапускаете карту. Пример реализации можно глянуть тут vertikal-invest.ru файл script.js
Понял, буду пробовать, спасибо. Просто я как вижу js, так сразу начинается паника.
И у меня еще один вопрос. При максимальном увеличении карты, все ок, но как только начинаю отдалять, точки начинают съезжать на встречу друг к другу, видать для того, что бы потом объединиться. Как это можно убрать? Кластеризация пускай остается, но точки при этом не ездили бы на встречу друг к другу, оставались статично на одном месте.
Спасибо.
Чтобы js-а не бояться посмотрите этот курс, я после него стал js понимать. Маркеры на карте всёравно будут съезжаться, они должны в кластеры собираться (смотрите решение тут vertikal-invest.ru), это нельзя убрать (если правильно понял о чём вы говорите), это работают скрипты яндекса, api карт.
За курс спасибо, обязательно ознакомлюсь. На сайте как раз все отлично с метками, они съезжают из-за уменьшения размера карты(при этом точки остаются прежнего размера) из-за этого как бы и съезжают.
У меня есть точка, расположение ее находится в Москве, если я максимально отдаляю, точка идет почти на северный полюс.
Если я от максимально приближенного размера два-четыре раза отдалю, то точка перепрыгивает на соседнюю улицу(постепенно с каждым кликом все выше и выше).
Добрый день. Сделали данную штуку у себя на портале Битрикс, менеджеры заводят объекты, они отображаются на карте, руководитель видит работу менеджера :). Ну буквально месяц назад, перестала отображаться карта, объекты заводятся все хорошо, но на странице форматирования карты пустой контейнер. Вопрос, а в данной карте есть ограничения по количеству объектов на карте? Если нет, что могло случится предположительно, доступа к админке Битрикс ни у кого нет блок новостей не правился..
Никаких ошибок JS не выдаёт? По идеи ограничений нет, возможно что у самого яндекса что-то поменялось, но вы бы наверняка увидели бы ошибки в консоли (F12 в Chrome), а может яндекс затребовал ключ доступа (возможно есть ограничения на использования API яндекс карт без ключа, token, возможно яндкес посчитал что у вас какое-то коммерческое приложение с кучей объектов на карте). Я бы написал в яндекс.
Добрый день. Спасибо за решение. Подскажите пожалуйста, а как сделать, чтобы карта появлялась не (center: [47.223572, 39.725845], //Создаём карту с центром в городе «Ростов-на-Дону»), а по координатам элемента. Поясню: создан ИБ — Россия — Санкт-Петербург, Москва, Ростов-на-Дону и т.д. с магазинами в этих городах и прописанными координатами. Сейчас открывается карта с центром прописанных координат в JS, а мне нужно чтобы она открывалась по координатам при нажатии на Москва, Ростов-на-Дону, Санкт-Петербург и т.д. центровалась по этим регионам. Москва — список магазинов — Карта с центровкой Москвы. И также при нажатии на другие регионы.
Спасибо.
Создайте доп.свойста у ИБ куда пропишите координаты нужных городов, а дальше аналогично (data-yandex-x, data-yandex-y) нужно вывести эти координаты в отдельный контейнер (какой-нибудь невидимый span с data-атрибутами) и считав из него значения подстваить их в атрибут center: [коордианты вашего города].
Здравствуйте
вывдит не одну а кучу карт, то есть для каждого элемента инфоблока.
а не одну общую карту для всех
либо выводит список элементов инфоблока, карту снизу и все.
Ну вы скорее всего поместили в цикл создание самой карты, проверьте чтобы объект var map = new ymaps.Map(«map_container») у вас создавался один (причём map_container — id единственного элемента, проверте чтобы map_container был один в html), так же выведите в консоль Placemark, точки на карте, что туда попадает. Конкретней сказать не могу, надо код смотреть =)
Все получилось.
Спасибо.
Очень полезный материал.
подскажите как убрать нумерацию у точек?
iconContent: "
" — надо
$(this).attr("data-index")
убрать помоему =)Подскажите, куда лучше вставить start.js? В шаблон страницы или шаблон компонента?
А это уже как вам будет удобнее. Я например всё в шаблоне сайта храню, чтобы не искать скрипты по компонентам.
Странно. Вроде все по инструкции, а карта не работает. И еще данные о скрипте где то в кэш падают. Пока не переименуешь имя файла изменения в коде не работают.
Словом выводится список элементов, под списком карта, а на карте только цифры вместо меток.
Помогите кто нибудь пожалуйста…
Вот скрин https://yadi.sk/i/XI2l5jG73Jcxxb
Убрал вот этот кусок
Адрес:
Часы работы:
Контактный телефон:
ФИО руководителя:
Список пропал. На карте данные есть. Только не работает оформление меток.
Точнее вот этот кусок
https://yadi.sk/i/bCm_p8JR3Jcykk
Во первых проверьте правильность путей к картинкам, это параметры в скрпте iconImageHref и iconactive , прямо откройте их в браузере и посмотрите что покажет Что касается кеша, думаю вы подключили скрипты напрямую, а надо через ядро с использованием метода $APPLICATION->AddHeadScript(), тогда с кешем проблем не будет.
Что касается пути, то он выглядит так.
iconImageHref: ‘/images/map.png’, //Путь к картинке точки
И можно буквально пару слов о подключении скриптов?
Спасибо вам огромное за решение. Давно искал.
Я имел ввиду у вас картинка открывается по этому пути (в браузере #ваш_сайт#/images/map.png )? По скриптам всё в доках есть https://dev.1c-bitrix.ru/api_help/main/reference/cmain/addheadscript.php , рекомендую так же к прохождению курс https://academy.1c-bitrix.ru/training/course/5862/ , там все эти вопросы подробно раскрываются.
Ok. Цифры на карту выводятся. Картинки из браузера доступны.
Если нажать на цифру — данные видно. Кластеризация отрабатывает — пишет при масштабировании «2 шт.». Значит скрипт отрабатывает.
Но метки все равно не видно. Куда еще можно капнуть?
Даже не знаю, надо смотреть конкретно.
Вы были правы — нужно было через ядро скрипты подключить.
Все работает — отличный метод, спасибо!
Здравствуйте, почему то тут пуста и метки непонятно где
<div
class="shop-data"
data-index="3"
data-name="есть тут"
data-yandex-x=""
data-yandex-y=""
data-address=""
data-hours=""
data-phone=""
А вы задали элементам инфоблока координаты? Свойство YANDEX_MAP не пустое?
Не работает в 18 версии битрикса!!!!
Что конкретно не работает? У вас яндекс карта не запускается или что? В статье описано использование функционала битрикса который не менялся в 18-й версии. Если у вас не работает карта, убедитесь что вы получили api ключ, сейчас он обязательный как для коммерческого так и для бесплатного использования яндекс.карт. Без api ключа карта может не работать без явных ошибок в консоли. Общались на этот счёт с ребятами из яндекса в декабре прошлого года.
А как сделать список объектов карты сделать активным как тут в апи:
https://tech.yandex.ru/maps/jsbox/2.1/object_list
там пример без кластера
Можете JSON собрать с объектами из данных инфоблока так как описано в groups.js. Что у вас не получается?