Создание пользовательского контрола карты с помощью API Яндекс.Карт 2.0


    Есть у карт Рамблера одно интересное дизайнерское решение, отсутствующее в других картах. Это контрол центра карты, благодаря которому показывается на что направлен текущий центр карты. Именно на примере этой функциональности я бы хотел рассказать вам о том, как сделать свой контрол для карт на своем сайте.

    Создание контрола разделим на нескольких этапов.

    Шаг 1. Лейаут.


    Лейаут, он же макет. Эта сущность отвечает за внешний вид элемента на карте. В нашем случае это крестик, при наведении на который будут показываться координаты центра карты. Создавать макет мы будем с помощью специальной фабрики templateLayoutFactory.

    var CrossCenterLayout = ymaps.templateLayoutFactory.createClass('<div id="cross-center" style="left:$[options.position.left]px;top:$[options.position.top]px;">+</div>', {
            build: function() {
                CrossCenterLayout.superclass.build.call(this);
                this._controlListeners = this.events.group().add('mouseenter', this.onCenterEnter, this).add('mouseleave', this.onCenterLeave, this);
                // запоминаем ссылку на карту, в которую добавлен контрол
                this._map = this.getData().map;
            },
            clear: function() {
                this._controlListeners.removeAll();
                CrossCenterLayout.superclass.clear.call(this);
            },
            onCenterEnter: function() {
                var center = this._map.getCenter();
                var lat = center[0].toFixed(2);
                var lng = center[1].toFixed(2);
                // показываем в центре карты хинт с координатами центра карты
                this._map.hint.show(center, {
                    content: lat + ', ' + lng
                });
            },
            onCenterLeave: function() {
                // скрываем хинт
                this._map.hint.hide();
            }
        });
    

    Рассмотрим код подробно. Фабрика templateLayoutFactory принимает на вход 2 параметра, шаблон будущего макета и список методов создаваемого лейаута, которые могут переопределять методы родительского класса.
    В нашем случае мы переопределяем методы build и clear, а так же добавляем свои методы onCenterEnter и onCenterLeave. В методе build добавляем в контейнер менеджера событий подписки на mouseleave и mouseenter.
    В методе clear мы от этих подписок избавляемся.

    Шаг 2. Класс контрола.


    var CrossCenter = function() {
        this.events = new ymaps.event.Manager();
        this.options = new ymaps.option.Manager();
        this.state = new ymaps.data.Manager();
    };
    
    CrossCenter.prototype = {
        setParent: function(parent) {
            this.parent = parent;
            if (parent) {
                var map = parent.getMap();
                this.layout = new CrossCenterLayout({
                    // передаем в лейаут данные о карте, на которую добавлен контрол и о его опциях
                    map: map,
                    options: this.options
                });
                // контрол будет добавляться в pane контролов
                this.layout.setParentElement(map.panes.get('controls').getElement());
            } else {
                this.layout.setParentElement(null);
            }
        },
        getParent: function() {
            return this.parent;
        }
    };
    

    Это, пожалуй, самая трудная часть кода. Тут мы реализуем интерфейс IControl. Сначала задаем обязательные поля, с помощью соответствующих менеджеров event, optionи data. Затем реализуем методы setParent и getParent. Первый был подсмотрен в исходных кодах апи, благодаря режиму debug, а второй, я думаю, вопросов не вызывает.

    Шаг 3. Добавление на карту


    С учетом стиля
    #cross-center{
        font-size: 20px;
        cursor: pointer;
        position: absolute;
        z-index: 800;
    }
    

    и контейнера карты
    <div id="map" style="height: 300px; width: 420px;"></div>
    

    создаем контрол и добавляем его в центр карты
    var crossCenter = new CrossCenter();
    map.controls.add(crossCenter, {
        top: 140,
        left: 200
    });
    

    Посмотреть результат трудов.

    P.S. Чтобы было совсем как у Рамблера, в метод onCenterEnter можно добавить обратное геокодирование, изменяя параметр kind в зависимости от текущего зума карты.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 4

      +4
      Немного настораживает надпись в правом нижнем углу «Яндекс Воскрес».
        0
        Справедливости ради, крест по центру имеется у kosmosnimki.ru, т.е. у используемого там GeoMixer. При том координаты (аж в трех форматах) показываются удобно в правом нижнем углу.
          0
          Кто знает что будет после команды
          this.layout.setParentElement(map.panes.get('controls').getElement());
          Подсказка — layout работает через innerHTML и это действие молча уничтожит все другие контролы.
          Лучше спросить у своего parent место где нас хотят разместить
          И да, вашим позиционированием занимается родитель(через ту ноду что выдает), а не ваш лайаут.
            0
            Пожалуй приведу, более верную конструкцию с замечаниями kashey.
              this.layout.setParentElement(parent.getChildElement(this));
            

            Вообще говоря от нового API остались двоякие ощущения, с одной стороны некоторые вещи стали делаться проще и логичнее, а другие стали более запутанными. К примеру раньше свой элемент управление было создать гораздо проще. Да я понимаю, что теперь это стало более расширяемым и создаваемые нами объекты не отличаются от стандартных, но очень часто этого и не нужно.
            Но скорость работы действительно увеличилась, да и появился новый функционал в стандартных объектах, которого так не хватало.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое