Клуб API Карт

Исправляем проблему autoPan c кастомным баллуном

Пост в архиве.

Эта проблема несколько раз уже поднималась в клубе API Яндекс Карт.
 

 

 

Оригинал статьи - тут с подсветкой кода


При открытии баллуна неправильно работает смещение карты и часть баллуна зарезается

Одним из решений было "прибивать" баллун к низу карты. Этот метод я реализовал в проекте
http://pomnivoinu.ru/map (желкните на объект, затем - "Подробнее"). В этом проекте - баллун довольно большой и содержит много контента с вкладками, и юзер (по замыслу) должен задержаться на этом баллуне. Поэтому "прибивать" его к низу карты было оправдано.

Баллун прибит к низу карты

 

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

 

balloonLayout = ymaps.templateLayoutFactory.createClass(
// шаблон баллуна у нас лежит в тэге <script type="text/html">
                $('#balloonContentTemplate').html(), {
                build: function() {
// исполняем конструктор суперкласса
                    balloonLayout.superclass.build.call(this);
// получает геообъект
                    var geoObject = this.getData().geoObject,
// карту
                        map = geoObject.getMap(),
// координаты геообъекта
                        coords = geoObject.geometry.getCoordinates(),
// контейнер баллуна
                        container =  $(this.getParentElement());
// смещаем контейнер баллуна относительно его привязки, чтобы получилось, что баллун находится по центру над геообъектом
                    container.find('.partner-balloon').each( function() {
                            $(this).css( {
                                left: -Math.round($(this).outerWidth() / 2),
                                top: -$(this).outerHeight()
                            });
                            var zoom = map.getZoom(),
                                width = $(this).outerWidth(),
                                height = $(this).outerHeight(),
                                projection = map.options.get('projection'),
// переводим геокоординаты геообъекта в пиксельные
                                global = projection.toGlobalPixels(coords, zoom),
// получаем пиксельные координаты центра карты
                                center = map.getGlobalPixelCenter(),
// получаем прямоугольник баллуна в пиксельных координатах
// прямоугольник смещаем над точкой посередине
                                balloonGlobalBounds = [ [ global[0] - Math.round(width / 2), global[1] + 0],
                                    [ global[0] + Math.round(width / 2), global[1] - height - 17]],
                                bounds = map.getBounds(),
// получаем вьюпорт карты в пиксельных координатах
                                globalBounds = [ projection.toGlobalPixels(bounds[0], zoom),
                                    projection.toGlobalPixels(bounds[1], zoom)],
// инициализируем смещение
                                pan = [ 0, 0];
// проверяем, находится ли прямоугольник баллуна внутри прямоугольника вьюпорта
// если нет, то смещаем его и прибавляем 20 пикселей для красоты
                            if ( balloonGlobalBounds[0][0] < globalBounds[0][0] ) {
                                pan[0] = balloonGlobalBounds[0][0] - globalBounds[0][0] - 20
                            } else if ( balloonGlobalBounds[1][0] > globalBounds[1][0]) {
                                pan[0] = balloonGlobalBounds[1][0] - globalBounds[1][0] + 20
                            }
                            if ( balloonGlobalBounds[0][1] > globalBounds[0][1] ) {
                                pan[1] = balloonGlobalBounds[0][1] - globalBounds[0][1] + 20
                            } else if ( balloonGlobalBounds[1][1] < globalBounds[1][1]) {
                                pan[1] = balloonGlobalBounds[1][1] - globalBounds[1][1] - 20
                            }
                            if (pan[0] || pan[1]) {
                                center[0] += pan[0];
                                center[1] += pan[1];
// вызываем panTo
                                map.panTo(projection.fromGlobalPixels(center, zoom), { delay: 0, duration: 500});
                            }

                        }).
                        on('click', '.ymaps-b-balloon__close', function() {
                              map.balloon.close();
                        });
                },
                clear: function() {
                    $('.partner-balloon').off();
                    balloonLayout.superclass.clear.call(this);
                }
            })


в результате получаем правльное расположение баллуна