Вывод данных из свойства заказа типа «Список» на интерактивную карту

Родион  Абдурахимов

Веб-разработчик

Вывод данных из свойства заказа типа «Список» на интерактивную карту

Рассмотрим ситуацию, когда при оформлении заказа, пользователь должен иметь возможность выбрать пункт выдачи товара, список которых хранится в свойстве заказа типа «Список». Такой пункт выдачи имеет свое название и адрес, после оформления заказа пользователем, менеджер магазина должен увидеть данные по пункту выдачи в сохраненном заказе. В этом посте мы покажем как можно вывести такой список адресов на Яндекс карту с возможностью выбирать конкретный адрес прямо на карте и сохранять этот выбор в значение свойства заказа.

Настройка свойства заказа типа «Список»

Для начала давайте рассмотрим как мы будем хранить данные по пунктам выдачи в свойстве заказа. Ниже на скриншоте показан пример заполнения нескольких пунктов выдачи:

На скриншоте изображены такие столбцы:

  • Код — служебное поле, может назначаться автоматически системой,
  • Название — та строка, которая будет видна пользователю и менеджеру по заказам,
  • Сорт. — сортировка, определяет порядок пункта выдачи в списке
  • Описание — данные для построения точки на карте: широта и долгота через запятую с пробелом. Пример — 59.966399, 30.338227

Код свойства должен быть равен DELIVERY_POINT, так как мы будем в дальнейшем использовать его для определения в цикле по свойствам в шаблоне оформления заказа.

Вывод списка на карту в компоненте оформления заказа

Теперь перейдем к выводу адресов на карту. В примерах будет использован компонент sale.order.ajax. Реализацию опишем в несколько этапов: подготовка и вывод всего необходимого HTML-кода и потом подключение JavaScript-кода, который «оживит» нашу карту.

Этап 1. Редактирование вывода свойства для дальнейшего подключения карты.

Перейдем в файл props_format.php шаблона компонента и в функции PrintPropsForm() найдем место, где обрабатываются свойства типа «Список». Это место должно быть в услсвии такого вида:


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/props_format.php
    ...
    elseif ($arProperties["TYPE"] == "SELECT")
    {
        //код для вывода свойства типа "Список"
    }
    ...

Перед закрывающей фигурной скобкой добавим такой код:


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/props_format.php
    ...
    <?//generating map for choosing delivery point?>
    <?if($arProperties["CODE"] == "DELIVERY_POINT"):?>
        <?foreach($arProperties["VARIANTS"] as $arVariants):?>
            <div class="js-map-coordinates hidden" data-coordinates="[<?=$arVariants["DESCRIPTION"]?>]" data-marker-index="<?=$arVariants["ID"]?>">
                <div class="baloon-content-wrap" style="margin-right: 0px;">
                    <div class="baloon-content-wrap-inner">
                        <p><strong><?=$arVariants["NAME"]?></strong></p>
                        <p><a class="choose-delivery-point" onclick="initChoosePoint(<?=$arVariants["ID"]?>)">Выбрать</a></p>
                    </div>
                </div>
            </div>
        <?endforeach;?>
        <div id="map" style="height: 400px; width: 700px; margin-top: 20px"></div>
    <?endif?>
    ...

Что мы тут сделали: мы вставил проверку на определение свойства для пунктов выдачи по его коду $arProperties["CODE"] == "DELIVERY_POINT", далее мы зарядили цикл по списку пунктов выдачи, которые мы настроили в предыдущем шаге. В этом цикле мы строим скрытые блоки и передаем в них информацию для построения точек на карту и ссылки для применения этого адреса в сохраненный заказ.

Также нужно добавить сам скрипт карты Яндекса:


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/template.php
    ...
    <script type="text/javascript" src="http://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
    ...

Этап 2. Добавления JavaScript-кода для построения карты

Перейдем в файл script.php шаблона компонента и добавим код для генерации карты


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/script.js
    
    var myMap,
    placemarks = [];
    var mapZoom = 10;
    function init() {
        var $firstCoordinates = $('.js-map-coordinates').eq(0),
            MyBalloonLayout = ymaps.templateLayoutFactory.createClass(
                '<div class="popover-balloon">' + '<div class="arrow"></div>'
                    + '<div class="popup-decor"></div>' + '<div class="popover-inner">'
                    + '$[[options.contentLayout observeSize minWidth=315 maxWidth=415]]' + '</div>' + '</div>',
                {

                    build: function () {
                        this.constructor.superclass.build.call(this);
                        this._$element = $('.popover-balloon', this.getParentElement());
                        this.applyElementOffset();
                    },
                    clear: function () {
                        this._$element.find('.close').off('click');
                        this.constructor.superclass.clear.call(this);
                    },
                    onSublayoutSizeChange: function () {
                        MyBalloonLayout.superclass.onSublayoutSizeChange.apply(this, arguments);
                        if (!this._isElement(this._$element)) {
                            return;
                        }
                        this.applyElementOffset();
                        this.events.fire('shapechange');
                    },
                    applyElementOffset: function () {
                        this._$element.css(
                            {
                                left: -(this._$element[0].offsetWidth / 2),
                                top: -(this._$element[0].offsetHeight + this._$element.find('.arrow')[0].offsetHeight)
                            }
                        );
                    },
                    _isElement: function (element) {
                        return element && element[0] && element.find('.arrow')[0];
                    }
                }
            ),
            MyBalloonContentLayout = ymaps.templateLayoutFactory.createClass(
                '<div class="popover-content">$[properties.balloonContent]</div>'
            ),
            clusterer = new ymaps.Clusterer({gridSize: 32});

        myMap = new ymaps.Map(
            "map",
            {
                center: $firstCoordinates.data('coordinates'),
                zoom: mapZoom
            }
        );

        $('.js-map-coordinates').each(
            function (index) {
                var coordinates = $(this).data('coordinates');

                if ($(this).find('.map-image').length === 0) {
                    $(this).find('.baloon-content-wrap').css('margin-right', '0');
                }
                placemarks[index] = new ymaps.Placemark(
                    coordinates,
                    {
                        balloonContent: $(this).html()
                    },
                    {
                        balloonShadow: false,
                        balloonLayout: MyBalloonLayout,
                        balloonContentLayout: MyBalloonContentLayout,
                        balloonPanelMaxMapArea: 0,
                        baloonAutoPan: 0,
                        hideIconOnBalloonOpen: false,

                        iconLayout: 'default#image',
                        hasCloseButton: false
                    }
                );

                placemarks[index].events.add(
                    'click',
                    function (e) {
                        var thisPlacemark = e.get('target'),
                            coords = thisPlacemark.geometry.getCoordinates();

                        myMap.panTo(coords);
                    }
                );
            }
        );

        clusterer.add(placemarks);
        clusterer.options.set({clusterIconColor: '#5abb4c'});
        myMap.geoObjects.add(clusterer);
    }

К этому коду нам нужно еще добавить обработчик события на клик для ссылки «Выбрать», которая будет выбирать нужный пункт выдачи прямо из карты:


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/script.js
    ...
    function initChoosePoint(optionId) {
        $("option#" + optionId).attr("selected", "selected");
    }
    ...

Нам также понадобится функция, которая будет запускать этот весь механизм, назовем ее initMap() и добавим под функцией initChoosePoint():


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/script.js
    ...
    function initMap() {
        var $map = $('#map');

        if ($map.length === 0 || $map.html().length) {
            return;
        }

        if ($map.length > 0) {
            if ($map.data('zoom')) {
                mapZoom = $map.data('zoom');
            }
            ymaps.ready(init);
        }
    }
    ...

Не стоит забывать, что мы работаем в компоненте sale.order.ajax, в котором любое действие пользователя приводит к ajax-перезагрузке области компонента и нам нужно заново инициировать все скрипты, что добавили. Код ниже строит карту по загрузке страницы, а также регистрирует обработчик на событие окончания ajax-запроса компонента и построит карту заново после каждой ajax-перезагрузки компонента:


    Файл home/путь_к_шаблонам_компонентов/sale.order.ajax/script.js
    ...
    $(window).load(function () {
        initMap();
        BX.addCustomEvent("onAjaxSuccess", initMap);
    });
    ...

Этап 3. Добавления CSS для построения карты

Для корректного отображения меток на карте нужно добавить такие CSS стили


 <style>
.baloon-content-wrap {
    width: 252px;
    margin-right: 120px;
    padding: 0 15px 0 30px;
    position: relative;
    background: #fff;
    box-shadow: 0 5px 5px rgba(0, 0, 0, .16);
    border: 2px solid #c5c5c5;
}
.baloon-content-wrap .baloon-content-wrap-inner {
    padding: 13px 15px 0 0;
    overflow: auto;
}
.choose-delivery-point {
    cursor: pointer;
}
.hidden {
  display:none;
}
</style>

Результат

Мы видим наших два пункта выдачи, при клике на точку на карте, мы можем его выбрать и в верхнем списке адресов будет применен выбранный адрес.

Похожие посты

Мы подобрали посты, которые могут быть вам интересны

Комментарии

Тут без вас никак. Поделитесь с нами вашими мыслями

  • Сделал все как написано, по клику на кнопку выбор ничего не происходит
  • Есть ли ошибки в консоли браузера? если эта страница в открытом доступе, предоставьте, пожалуйста, ссылку, я могу проверить
  • В консоли ошибок нет, вот ссылка на сайт http://ci08889.tmweb.ru/, при оформлении заказа внизу появляется карта, после выбора пункта самовывоз
  • Скорее всего у вас в конфликте стандартная битирксовая карта для выбора склада, так как она тоже подключает свои скрипты на странице. Попробуйте временно отключить возможность выбора склада на самовывозе
  • Спасибо, сейчас попробую....
  • Если убрать все склады самовывоза, то карта не загружается...
  • Я вижу, что на самовывозе все также всплывает карта со складами, смотрю тут http://ci08889.tmweb.ru/personal/order/make/, ничего не изменилось
  • Сейчас еще раз уберу....
  • Убрал
  • В консоле ошибка - Uncaught ReferenceError: ymaps is not defined попробуйте добавить в template.php копонента заказа строку сразу после
  • Карта появилась, но выбор по прежнему не работает
  • Виноват, добавил в статью этап 3, нужно внести несколько css-правил для корректоного отображения блоков на карте По поводу выбора селекта я вижу, что в самих option нет атрибута id, а он должен совпадасть в параметре функции initChoosePoint() с атрибутом id в option. Например в вашем случае - "г. Воронеж, ул. Олеко Дундича, 1" у него в option value="a1", а в функции вызывается initChoosePoint(1), по этому не идет выбор селекта из карты. Попробуйте в месте, где строится
  • Добавил к option id, добавил css, исправил ошибку в блоках, теперь поле select стало скрытым и соответственно не видно, что выбрал, потом убрал стиль hidden появилось поле select, но при нажатии с карты отрабатывает только 1 раз...
  • возможно вам поможет увидеть все в собранном состоянии на вот этот проекте http://shop.shp-losevo.ru/, сравните код, который у вас и там, есть отличия
  • У меня почему-то по клику с карты отмечается option как selected и при повторном клике не удаляется... То есть все опции отмечены как выбранные
Горячие вакансии